import MSLogger; log = MSLogger.get('wsgi_server')
import MSObject
import threading
import os

def genObjects(path):
    if not os.path.exists(path): return
    for f in os.listdir(path):
        if f[0] == '.': continue
        if f.find('.info') == -1: continue

        name = f.split('.info')[0]
        obj = MSObject.MSObject(path, name)
        obj.open()
        if obj.storage.txn == 0: continue
        yield (obj.objId, obj)

class MSObjects:
    def __init__(self, path):
        self.path = path
        self.objs = {}
        self.lock = threading.Lock()

    def load(self):
        self.lock.acquire()
        try:
            log.debug('Objects::load: ...')
            for oid,obj in genObjects(self.path):
                if not self.objs.has_key(oid):
                    obj.load()
                    log.debug('loaded %s object: msId(%s) evnum(%d)', oid, obj.storage.meta['msId'], len(obj.events))
                    self.objs[oid] = obj
            log.info('Objects::load: done')
        finally:
            self.lock.release()

    def flush(self):
        self.lock.acquire()
        try:
            log.debug('Objects::flush: ...')
            for oid,obj in self.objs.iteritems():
                log.debug('flushing %s object: msId(%s) evnum(%d)', oid, obj.storage.meta['msId'], len(obj.events))
                obj.flush()
            log.info('Objects::flush: done')
        finally:
            self.lock.release()

    def archive(self):
        self.lock.acquire()
        try:
            log.debug('Objects::archive: ...')
            for oid,obj in self.objs.iteritems():
                log.debug('archiving %s object: msId(%s) evnum(%d)', oid, obj.storage.meta['msId'], len(obj.events))
                obj.archive()
            log.info('Objects::archive: done')
        finally:
            self.lock.release()

    def find(self, objId, Locked=False):
        if not Locked: self.lock.acquire()
        try:
            if self.objs.has_key(objId): return self.objs[objId]
            return None
        finally:
            if not Locked: self.lock.release()

    def destroy(self, objId):
        self.lock.acquire()
        try:
            if self.objs.has_key(objId):
                obj = self.objs.pop(objId) 
                obj.flush() #TBD rm
                obj.destroy()
            log.info('Objects::destroy: %s done', objId)
        finally:
            self.lock.release()


##########################
if __name__ == "__main__":
    import sys
    if len(sys.argv) != 2: print "Usage: %s <storage_root>" % (sys.argv[0])
    g_root = sys.argv[1]

    def case1():

        o = MSObject.MSObject(g_root, 'test_obj')
        o.open()
        o.storage.destroy()

        objs = MSObjects(g_root)
        objs.load()

        o = MSObject.MSObject(g_root, 'test_obj')
        o.open()
        o.storage.meta['msId'] = 79
        o.append([1, 2, 3])
        o.flush()

        t = objs.find('test_obj')
        if t != None: raise RuntimeError('case1: failed 1')

        objs.load()
        t = objs.find('test_obj')
        if t == None: raise RuntimeError('case1: failed 2')

    def case2():
        objs = MSObjects(g_root)
        objs.load()

        o1 = objs.find('test_obj')
        if o1.storage.meta['msId'] != 79: raise RuntimeError('case2: failed 1')
        if o1.events != [1, 2, 3]: raise RuntimeError('case2: failed 2')
        e1 = o1.events

        objs.find('test_obj').append([3, 4, 5])
        objs.flush()

        o2 = objs.find('test_obj')
        if o1.events != [1, 2, 3, 4, 5]: raise RuntimeError('case2: failed 3')
        if o1.events != o2.events: raise RuntimeError('case2: failed 4')
        if o1.txn != 2: raise RuntimeError('case2: failed 5')
        if e1 != [1, 2, 3]: raise RuntimeError('case2: failed 6')

    case1()
